﻿namespace GeoSketch2.Core
{
    /// <summary>
    /// The 3D point class for the geosketch application, coordinates are integers
    /// </summary>
    public class Point3D32S
    {
        #region Fields
        /// <value name="X">The X-coordinate of the point</value>
        /// <value name="Y">The Y-coordinate of the point</value>
        /// <value name="Z">The Z-coordinate of the point</value>
        public int X, Y, Z; 
        #endregion

        #region Constructor
        /// <summary>
        /// 3D Point with an integer precision
        /// </summary>
        public Point3D32S()
        {
            X = 0;
            Y = 0;
            Z = 0;
        }

        /// <summary>
        /// 3D Point with an integer precision
        /// </summary>
        /// <param name="X">The X-coordinate of the point</param>        
        /// <param name="Y">The Y-coordinate of the point</param>        
        /// <param name="Z">The Z-coordinate of the point</param>               
        public Point3D32S(int X, int Y, int Z)
        {
            this.X = X;
            this.Y = Y;
            this.Z = Z;
        }
        #endregion

        #region Operators
        /// <summary>
        /// Adds Point2 to Point1
        /// </summary>
        /// <param name="Point1">First point</param>
        /// <param name="Point2">Second point</param>
        public static Point3D32S operator +(Point3D32S Point1, Point3D32S Point2)
        {
            return new Point3D32S(Point1.X + Point2.X, Point1.Y + Point2.Y, Point1.Z + Point2.Z);
        }

        /// <summary>
        /// Negates the point
        /// </summary>
        /// <param name="Point">The point to negate</param>
        public static Point3D32S operator -(Point3D32S Point)
        {
            return new Point3D32S(-Point.X, -Point.Y, Point.Z);
        }
        #endregion
    }

    /// <summary>
    /// The 3D point class for the geosketch application, coordinates are single precision numbers (float or single)
    /// </summary>
    public class Point3D32F
    {
        #region Fields
        /// <value name="X">The X-coordinate of the point</value>
        /// <value name="Y">The Y-coordinate of the point</value>
        /// <value name="Z">The Z-coordinate of the point</value>
        public float X, Y, Z; 
        #endregion

        #region Constructor
        /// <summary>
        /// Point with an integer precision
        /// </summary>
        public Point3D32F()
        {
            X = 0;
            Y = 0;
            Z = 0;
        }

        /// <summary>
        /// Point with a single precision
        /// </summary>
        /// <param name="X">The X-coordinate of the point</param>        
        /// <param name="Y">The Y-coordinate of the point</param>        
        /// <param name="Z">The Z-coordinate of the point</param>
        public Point3D32F(float X, float Y,float Z)
        {
            this.X = X;
            this.Y = Y;
            this.Z = Z;
        }
        #endregion

        #region Operators
        /// <summary>
        /// Adds Point2 to Point1
        /// </summary>
        /// <param name="Point1">First point</param>
        /// <param name="Point2">Second point</param>
        public static Point3D32F operator +(Point3D32F Point1, Point3D32F Point2)
        {
            return new Point3D32F(Point1.X + Point2.X, Point1.Y + Point2.Y, Point1.Z + Point2.Z);
        }

        /// <summary>
        /// Negates the point
        /// </summary>
        /// <param name="Point">The point to negate</param>
        public static Point3D32F operator -(Point3D32F Point)
        {
            return new Point3D32F(-Point.X, -Point.Y,-Point.Z);
        }
        #endregion
    }

    /// <summary>
    /// The 2D point class for the geosketch application, coordinates are double precision numbers (double)
    /// </summary>
    public class Point3D64D
    {
        #region Fields
        /// <value name="X">The X-coordinate of the point</value>
        /// <value name="Y">The Y-coordinate of the point</value>
        /// <value name="Z">The Z-coordinate of the point</value>
        public double X, Y, Z; 
        #endregion

        #region Constructor
        /// <summary>
        /// Point with an integer precision
        /// </summary>
        public Point3D64D()
        {
            X = 0;
            Y = 0;
            Z = 0;
        }

        /// <summary>
        /// Point with an integer precision
        /// </summary>
        /// <param name="X">The X-coordinate of the point</param>        
        /// <param name="Y">The Y-coordinate of the point</param>        
        /// <param name="Z">The Z-coordinate of the point</param>
        public Point3D64D(double X, double Y,double Z)
        {
            this.X = X;
            this.Y = Y;
            this.Z = Z;
        }
        #endregion

        #region Operators
        /// <summary>
        /// Adds Point2 to Point1
        /// </summary>
        /// <param name="Point1">First point</param>
        /// <param name="Point2">Second point</param>
        public static Point3D64D operator +(Point3D64D Point1, Point3D64D Point2)
        {
            return new Point3D64D(Point1.X + Point2.X, Point1.Y + Point2.Y, Point1.Z + Point2.Z);
        }

        /// <summary>
        /// Negates the point
        /// </summary>
        /// <param name="Point">The point to negate</param>
        public static Point3D64D operator -(Point3D64D Point)
        {
            return new Point3D64D(-Point.X, -Point.Y,-Point.Z);
        }

        /// <summary>
        /// Converts a point with integer coordinates to a point with double precision coordinates
        /// </summary>
        /// <param name="Point">Source point</param>
        public static implicit operator Point3D64D(Point3D32S Point)
        {
            return new Point3D64D(Point.X, Point.Y,Point.Z);
        }

        /// <summary>
        /// Converts a point with single precision coordinates to a point with double precision coordinates
        /// </summary>
        /// <param name="Point">Source point</param>
        public static implicit operator Point3D64D(Point3D32F Point)
        {
            return new Point3D64D(Point.X, Point.Y,Point.Z);
        }

        /// <summary>
        /// Converts a 2D point to its homogenized representation
        /// </summary>
        /// <param name="Point">Source point</param>
        public static implicit operator Point3D64D(Point2D64D Point)
        {
            return new Point3D64D(Point.X, Point.Y,1);
        }

        /// <summary>
        /// Converts a homogenized reprsentation to a 2D point
        /// </summary>
        /// <param name="Point">Source point</param>
        public static implicit operator Point2D64D(Point3D64D Point)
        {
            return new Point2D64D(Point.X/Point.Z, Point.Y/Point.Z);
        }
        #endregion
    }
}
